package com.imooc.pan.storage.engine.core;

import cn.hutool.core.lang.Assert;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.imooc.pan.cache.core.constants.CacheConstants;
import com.imooc.pan.core.constants.RPanConstants;
import com.imooc.pan.core.exception.RPanBusinessException;
import com.imooc.pan.core.exception.RPanFrameworkException;
import com.imooc.pan.storage.engine.core.context.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;

import java.io.IOException;
import java.util.Objects;

/**
 * 顶级文件存储引擎的公用父类
 * @author hhb
 * @data 2024/6/10 16:43
 */
public abstract class AbstractStorageEngine implements StorageEngine{
    @Autowired
    private CacheManager cacheManager;

    /**
     * 公用的获取缓存的方法
     * @return
     */
    protected Cache getCache(){
        if(Objects.isNull(cacheManager)){
            throw new RPanFrameworkException("the cache manager is empty!");
        }
        return cacheManager.getCache(CacheConstants.R_PAN_CACHE_NAME);
    }

    /**
     * 保存文件
     * @param context
     * @throws IOException
     */
    @Override
    public void store(StoreFileContext context) throws IOException {
        checkStoreFile(context);
        doStoreFile(context);
    }

    /**
     * 上传文件具体操作，下沉到子类
     * @param context
     * @throws IOException
     */
    protected abstract void doStoreFile(StoreFileContext context) throws IOException;

    /**
     * 校验上传文件参数
     * @param context
     */
    private void checkStoreFile(StoreFileContext context) {
        Assert.notBlank(context.getFilename(),"文件名称不能为空");
        Assert.notNull(context.getTotalSize(),"文件大小不能为空");
        Assert.notNull(context.getInputStream(),"文件输入流不能为空");
    }

    /**
     * 删除文件
     * @param context
     * @throws IOException
     */
    @Override
    public void delete(DeleteFileContext context) throws IOException {
        checkDeleteFile(context);
        doDeleteFile(context);
    }

    /**
     * 检查删除文件信息
     * @param context
     */
    private void checkDeleteFile(DeleteFileContext context) {
        Assert.notEmpty(context.getRealPathList(),"文件删除路径不能为空");
    }

    /**
     * 删除文件具体操作，下沉到子类
     * @param context
     * @throws IOException
     */
    protected abstract void doDeleteFile(DeleteFileContext context) throws IOException;


    @Override
    public void storeChunkFile(StoreChunkFileContext context) throws IOException {
        checkChunkFile(context);
        doSaveChunkFile(context);
    }

    /**
     * 存储分片文件
     * 下沉到子服务执行
     * @param context
     * @throws IOException
     */
    protected abstract void doSaveChunkFile(StoreChunkFileContext context) throws IOException;


    /**
     * 检查文件分片有效性
     * @param context
     */
    private void checkChunkFile(StoreChunkFileContext context) {
        Assert.notBlank(context.getFilename(),"文件名称不能为空");
        Assert.notBlank(context.getIdentifier(),"文件唯一标识不能为空");
        Assert.notNull(context.getTotalSize(),"文件总大小不能为空");
        Assert.notNull(context.getChunkNumber(),"文件下标不能为空");
        Assert.notNull(context.getInputStream(),"文件分片不能为空");
        Assert.notNull(context.getCurrentChunkSize(),"文件当前大小不能为空");
        Assert.notNull(context.getTotalChunks(),"文件总分片个数不能为空");
        Assert.notNull(context.getUserId(),"当前登录用户的ID不能为空");
    }

    /**
     * 分片文件合并
     * @param context
     * @throws IOException
     */
    @Override
    public void mergeFile(MergeFileContext context) throws IOException {
        //文件合并校验
        checkMergeFile(context);
        //执行合并操作
        doMergeFile(context);
    }

    /**
     * 文件合并校验
     * @param context
     */
    private void checkMergeFile(MergeFileContext context) {
        Assert.notBlank(context.getFilename(),"文件名称不能为空");
        Assert.notBlank(context.getIdentifier(),"文件唯一标识不能为空");
        Assert.notNull(context.getUserId(),"文件用户ID不能为空");
        Assert.notEmpty(context.getRealPathList(),"文件分片的存储路径不能为空");
    }

    /**
     * 存储分片文件
     * 下沉到子服务执行
     * @param context
     * @throws IOException
     */
    protected abstract void doMergeFile(MergeFileContext context) throws IOException;


    @Override
    public void readFile(ReadFileContext context) throws IOException {
        checkReadFile(context);
        doReadFile(context);
    }

    /**
     * 执行文件下载操作并写入到输出流中
     * 下沉到子类中去实现
     * @param context
     * @throws IOException
     */
    protected abstract void doReadFile(ReadFileContext context) throws IOException;

    /**
     * 校验下载文件参数
     * @param context
     */
    private void checkReadFile(ReadFileContext context) {
        Assert.notBlank(context.getRealPath(),"文件真实存储路径不能为空");
        Assert.notNull(context.getOutputStream(),"文件的输出流不能为空");
    }
}
